

function DragnDrop(base,targets,getBaseTrigger,cType){
	this.base = base;
	this.targets = targets;
	this.base.getBaseTrigger = getBaseTrigger || this.getBaseTrigger;
	this.getBaseTrigger = this.base.getBaseTrigger;
	
	if(cType)this.setHitTest(cType);
	
	return this;
}

DragnDrop.prototype = {
	constructor:DragnDrop,
	toString:function(){return "DragnDrop";},
	
	base:false,
	getBaseTrigger:function(){return this;},
	
	state:{p:'',x:0,y:0,z:0},
	position:'absolute',
	zIndex:1000,

	targets:[],
	colliders:[],
	oldColliders:[],
	
	grid:0,
	
	revertToBeggin:false,

	start:function(e){
		var d=this.DragnDrop, b=this.base;
			b.DragnDrop = d;

		d.move.base = b;
		d.stop.base = b;
		
		compono.Event.add("mousemove",d.move,document);
		compono.Event.add("mouseup",d.stop,document);			
			
		if(d.onDrag&&d.onDrag(b,e)==false){
			return false;
		}
		
		d.state.p = b.style.position;
		d.state.z = b.style.zIndex || 0;
		d.state.x = b.style.left;
		d.state.y = b.style.top;
		
		b.style.position = d.position;
		b.style.zIndex = d.zIndex;

		b.offsetLeftGap = (e.clientX-b.offsetLeft);
		b.offsetTopGap = (e.clientY-b.offsetTop);
		
		compono.appendClassName("dragging",b);

	},
	move:function(e){
		var o=arguments.callee.base;
		
		if(o.DragnDrop.onMove&&o.DragnDrop.onMove(o,e)==false){
			return false;
		}

		o.style.top=(e.clientY-o.offsetTopGap)+"px";
		o.style.left=(e.clientX-o.offsetLeftGap)+"px";
		
		// if(o.DragnDrop.constrain){
			// if(!o.DragnDrop.constructor.collision.type.boundingBox(o,o.DragnDrop.constrain)){
				// o.style.top=(o.oldOffSetTop)+"px";
				// o.style.left=(o.oldOffSetLeft)+"px";
			// }
		// }
		// o.oldOffSetTop = o.offsetTop;
		// o.oldOffSetLeft = o.offsetLeft;
		
		o.DragnDrop.hitTest(o,e);
	},
	stop:function(e){
		var o=arguments.callee.base;
		var d=o.DragnDrop;

		compono.Event.remove("mousemove",d.move,document);
		compono.Event.remove("mouseup",d.stop,document);
		
		if(d.onDrop&&d.onDrop(o,!!(d.colliders.length),d.colliders,e)==false){
			return false;			
		}
		
		if(d.revertToBeggin){
			d.revert(o);
		}
		compono.removeClassName("dragging",o);
	},
	
	run:function(targets,getBaseTrigger,collisionType){
		
		//Array or HTMLCollection
		var base = this.base.length && typeof(this.base)!="string" ? this.base : [this.base];
		var t = this.getBaseTrigger || function(){return this;};
		
		for(var i=0,m,b;b=base[i];i++){
			b.trigger = t.call(b,b);
			b.trigger.base = b;
			b.trigger.DragnDrop = this;
			b.trigger.unselectable="on";
			b.trigger.style.MozUserSelect="none";
			b.trigger.style.KhtmlUserSelect="none";
			compono.Event.add("mousedown",this.start,b.trigger);
		}
		
		if(targets){
			this.targets = targets;
		}
		
		this.setHitTest(collisionType);
		
		return this;
	},
	
	collisionType:"edgeBox",
	hitTest:function(){},
	setHitTest:function(collisionType){
		
		var hitTest;
		if(this.targets){
			if(this.targets.length>=0 && typeof(this.targets)!="string"){
				hitTest = this.constructor.collision.manyTargets;
			}else{
				hitTest = this.constructor.collision.oneTarget;
			}
		}else{
			hitTest = this.constructor.collision.nonTarget;
		}

		this.hitTest = hitTest;

		if(this.constructor.collision.type.hasOwnProperty(collisionType))
		{
			this.collisionType = collisionType;
			this.hitTest.type = this.constructor.collision.type[this.collisionType];
		}
		else if(typeof(collisionType)=="function")
		{
			this.hitTest.type = collisionType;
		}
		
		return this;
	},	
	
	revert:function(o){
		if(this.onRevert && this.onRevert(o) == false){ 
			return false;
		}
		o.style.position = this.state.p;
		o.style.zIndex = this.state.z;
		o.style.left = this.state.x;
		o.style.top = this.state.y;	
		return true;
	},
	
	onDrag:false,
	onCollide:false,
	onNotCollide:false,
	onDrop:false,
	onRevert:false
}

DragnDrop.collision = {
	nonTarget:function(a,e){},
	oneTarget:function(a,e){

		this.colliders=[];
		
		if(a !== this.targets){
			if(arguments.callee.type(a,this.targets))
			{
				this.colliders[this.colliders.length] = this.targets;
				if(this.onCollide){
					this.onCollide(a,this.targets,e);
				}
			}
			else if(this.onNotCollide)
			{
				this.onNotCollide(a,this.targets,e);
			}
		}
	},
	manyTargets:function(a){
		
		this.colliders=[];
		this.oldColliders=[];
		
		for(var i=0,b;(b=this.targets[i]);i++){
			if(a!==b && arguments.callee.type(a,b)){
				this.colliders[this.colliders.length] = b;
			}else{
				this.oldColliders[this.oldColliders.length] = b;
			}
		}
		
		if(this.onCollide&&this.colliders.length){
			this.onCollide(a,this.colliders,e);
		}

		if(this.onNotCollide&&this.oldColliders.length){
			this.onNotCollide(a,this.oldColliders,e);
		}
		
	},
	type:{
		/*When the box touch his target*/
		edgeBox:function(A,B){
			return !(	A.offsetLeft + A.offsetWidth < B.offsetLeft || 
						A.offsetLeft > B.offsetLeft + B.offsetWidth || 
						A.offsetTop + A.offsetHeight < B.offsetTop || 
						A.offsetTop > B.offsetTop + B.offsetHeight		);
		},
		/*When the box is totally inside of his target*/
		boundingBox:function(A,B){
			return (	A.offsetLeft > B.offsetLeft && 
						A.offsetLeft + A.offsetWidth < B.offsetLeft + B.offsetWidth && 
						A.offsetTop + A.offsetHeight < B.offsetTop + B.offsetHeight && 
						A.offsetTop > B.offsetTop		);
		},
		/*When the box is totally outside of his target*/
		externalBox:function(A,B){
			return (	A.offsetLeft + A.offsetWidth < B.offsetLeft || 
						A.offsetLeft > B.offsetLeft + B.offsetWidth || 
						A.offsetTop + A.offsetHeight < B.offsetTop || 
						A.offsetTop > B.offsetTop + B.offsetHeight		);
		}
	}
}